#include "UnionMgr.h"
#include "db_driver/db_driver.h"
#include "RelaSvr.h"
#include "RelaPlayerMgr.h"
#include "stl_boost.h"

#define RegRpc(fun) STATIC_RUN(RelaSvr::Ins().RegRpcFun(&UnionMgr::fun, UnionMgr::Ins(), #fun);)

UnionMgr& gUnionMgr = UnionMgr::Ins();
su::snowflake<> UnionMgr::s_createid;

REG_EVENT(EVENTID::ON_DB_CON, UnionMgr::OnDbCon)
void UnionMgr::OnDbCon()
{
	if (!gUnionMgr.m_id2union.empty())
	{
		return;
	}

	auto f = [](const std::string& data)
	{
		if (data.empty())
		{
			LDEBUG("load union finish. ");
			gRelaSvr.SetReady(ReadyType::LOAD_UNION);
		}
		else
		{
			auto pUnion = make_unique<Union>();
			TableCfg::Ins().UnpackForObj(pUnion->m_db, data);
			gUnionMgr.m_id2union.emplace(pUnion->Id(), std::move(pUnion));
		}
	};
	Dbproxy::Ins().QueryCondForMore(UNION_TABLE_ID, "", f, 2);
}

Union *UnionMgr::Find(uint64 id)
{
	auto it = m_id2union.find(id);
	L_COND(it != m_id2union.end(), nullptr);
	return it->second.get();
}

void UnionMgr::DelUnion(uint64 id)
{
	UnionOptMgr::Ins().AddOpt(id, [id](Union &_union) {
		Dbproxy::Ins().Del(_union.m_db, [id](bool isOk){
			if (!isOk)
			{
				LERROR("del union fail. ", id);
				return;
			}
			LDEBUG("del union ok. ", id);
			gUnionMgr.m_id2union.erase(id);
		});
	});
}

void UnionMgr::OnFiveMinute()
{
	for (auto& i : m_id2union)
	{
		if (i.second->m_bDirty)
		{
			i.second->SaveDb();
		}
	}
}

RegRpc(CreateNewUnion)
void UnionMgr::CreateNewUnion(const DbFriendBrief& owner, const std::string& name)
{
	LDEBUG("create new union", owner.id, name);
	uint64 id = s_createid.nextid();
	Union _union;//tmp object
	_union.m_db.id = id;
	_union.m_db.owner = owner;
	_union.m_db.id2Member.emplace( owner.id, DbUnionMem(owner.id) );

	RpcNetClient* con = RpcNetClient::GetCurCon();
	L_COND_V(con == &(gRelaSvr.m_ConToCenter));
	uint32_t snId = con->GetCurSnId();
	auto f = [id, name, snId](bool isOk)
	{
		if (!isOk)
		{
			gRelaSvr.m_ConToCenter.RetEx(snId, isOk);
			LWARN("insert pUnion fail. ", id, name);
			return;
		}
		UnionOptMgr::Ins().AddOpt(id, [id, name, snId](Union &_union) {
			gRelaSvr.m_ConToCenter.RetEx(snId, true);
		});
	};
	Dbproxy::Ins().Insert(_union.m_db, f);
}

void Union::SaveDb()
{
	if (!m_bDirty)
	{
		return;
	}
	Dbproxy::Ins().Update(m_db);
	m_bDirty = false;
}

void Union::UpdateMemberBrief(const DbFriendBrief &brief)
{
	DbUnionMem* pMem = su::MapFind(m_db.id2Member, brief.id);
	if (nullptr == pMem)
	{
		LERROR("miss member. ", brief.id);
		return;
	}
	pMem->lv = brief.lv;
	pMem->name = brief.name;

	m_bDirty = true;
}

Union *UnionOptMgr::OnFindTarget(uint64 target_id)
{
	return gUnionMgr.Find(target_id);
}

void UnionOptMgr::OnMissTarget(uint64 id)
{
	auto f = [id](const std::string& data)
	{
		if (data.empty())
		{
			LERROR("load union fail", id); 
			UnionOptMgr::Ins().OnLoadFail(id);
		}
		else
		{
			auto& id2data = gUnionMgr.m_id2union;
			auto it = id2data.find(id);
			L_COND_V( it == id2data.end());

			unique_ptr<Union>& un = id2data.emplace(id, make_unique<Union>()).first->second;
			TableCfg::Ins().UnpackForObj(un->m_db, data);
			UnionOptMgr::Ins().OnLoadOk(id, *un);
		}
	};
	
	string cond = "id = " + StrNum::NumToStr(id);
	Dbproxy::Ins().QueryCondRaw(UNION_TABLE_ID, cond, f);
}
